package com.itheima.admin.gateway.filter;

import com.alibaba.fastjson.JSON;
import com.itheima.admin.gateway.util.JwtUtil;
import io.jsonwebtoken.Claims;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.nio.charset.StandardCharsets;
import java.util.*;

/**
 * 权限校验过滤器
 * 基于RBAC模型，校验用户是否有权限访问特定资源
 */
@Slf4j
@Component
public class PermissionFilter implements GlobalFilter, Ordered {
    
    // 权限映射：路径 + 方法 -> 需要的权限
    private static final Map<String, String> PERMISSION_MAP = new HashMap<>();
    
    static {
        // ============ Dashboard 数据统计 ============
        PERMISSION_MAP.put("GET:/admin/api/v1/dashboard/stats", "dashboard:view");
        PERMISSION_MAP.put("GET:/admin/api/v1/dashboard/trends", "dashboard:view");
        
        // ============ 管理员管理 (/admin/api/v1/admin/**) ============
        PERMISSION_MAP.put("POST:/admin/api/v1/admin/list", "system:admin:view");
        PERMISSION_MAP.put("GET:/admin/api/v1/admin/*", "system:admin:view");  // GET /{id}
        PERMISSION_MAP.put("POST:/admin/api/v1/admin", "system:admin:create");
        PERMISSION_MAP.put("PUT:/admin/api/v1/admin/*", "system:admin:edit");  // PUT /{id}
        PERMISSION_MAP.put("DELETE:/admin/api/v1/admin/*", "system:admin:delete");  // DELETE /{id}
        PERMISSION_MAP.put("PUT:/admin/api/v1/admin/*/status", "system:admin:edit");  // PUT /{id}/status
        PERMISSION_MAP.put("PUT:/admin/api/v1/admin/*/password", "system:admin:edit");  // PUT /{id}/password
        PERMISSION_MAP.put("PUT:/admin/api/v1/admin/*/roles", "system:admin:edit");  // PUT /{id}/roles
        
        // ============ 角色管理 (/admin/api/v1/role/**) ============
        PERMISSION_MAP.put("GET:/admin/api/v1/role/list", "system:role:view");
        PERMISSION_MAP.put("GET:/admin/api/v1/role/*", "system:role:view");  // GET /{id}
        PERMISSION_MAP.put("POST:/admin/api/v1/role", "system:role:create");
        PERMISSION_MAP.put("PUT:/admin/api/v1/role/*", "system:role:edit");  // PUT /{id}
        PERMISSION_MAP.put("DELETE:/admin/api/v1/role/*", "system:role:delete");  // DELETE /{id}
        PERMISSION_MAP.put("PUT:/admin/api/v1/role/*/permissions", "system:role:edit");  // PUT /{id}/permissions
        
        // ============ 权限管理 (/admin/api/v1/permission/**) ============
        PERMISSION_MAP.put("GET:/admin/api/v1/permission/list", "system:permission:view");
        PERMISSION_MAP.put("GET:/admin/api/v1/permission/*", "system:permission:view");  // GET /{id}
        PERMISSION_MAP.put("POST:/admin/api/v1/permission", "system:permission:create");
        PERMISSION_MAP.put("PUT:/admin/api/v1/permission/*", "system:permission:edit");  // PUT /{id}
        PERMISSION_MAP.put("DELETE:/admin/api/v1/permission/*", "system:permission:delete");  // DELETE /{id}
        
        // ============ 用户管理（小程序用户） (/admin/api/v1/user/**) ============
        PERMISSION_MAP.put("GET:/admin/api/v1/user/list", "user:view");
        PERMISSION_MAP.put("GET:/admin/api/v1/user/*", "user:view");  // GET /{id}
        PERMISSION_MAP.put("PUT:/admin/api/v1/user/*/status", "user:status");  // PUT /{id}/status
        
        // ============ 内容审核 (/admin/api/v1/audit/**) ============
        PERMISSION_MAP.put("GET:/admin/api/v1/audit/notes", "audit:note:view");
        PERMISSION_MAP.put("PUT:/admin/api/v1/audit/notes/*", "audit:note:audit");  // PUT /notes/{id}
        PERMISSION_MAP.put("GET:/admin/api/v1/audit/reviews", "audit:review:view");
        PERMISSION_MAP.put("PUT:/admin/api/v1/audit/reviews/*", "audit:review:audit");  // PUT /reviews/{id}
    }
    
    // 不需要权限校验的路径
    private static final String[] NO_PERMISSION_CHECK_LIST = {
            "/auth/api/v1/auth",          // 认证相关接口
            "/auth/api/v1/wechat",        // 微信登录相关
            "/doc.html",                  // API文档
            "/swagger",                   // Swagger
            "/webjars",                   // 静态资源
            "/favicon.ico"                // 图标
    };
    
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();
        
        String path = request.getURI().getPath();
        String method = request.getMethod().name();
        
        // 1. 不需要权限校验的路径直接放行
        if (isNoPermissionCheckPath(path)) {
            return chain.filter(exchange);
        }
        
        // 2. 获取token（AuthFilter已经验证过token有效性）
        String token = getToken(request);
        if (StringUtils.isBlank(token)) {
            // 如果没有token，说明是白名单路径，直接放行
            return chain.filter(exchange);
        }
        
        try {
            // 3. 从token中获取权限列表
            Claims claims = JwtUtil.getClaims(token);
            @SuppressWarnings("unchecked")
            List<String> userPermissions = (List<String>) claims.get("permissions");
            
            // 4. 超级管理员拥有所有权限
            @SuppressWarnings("unchecked")
            List<String> roles = (List<String>) claims.get("roles");
            if (roles != null && roles.contains("SUPER_ADMIN")) {
                log.info("超级管理员访问，跳过权限校验");
                return chain.filter(exchange);
            }
            
            // 5. 检查是否需要特定权限
            String requiredPermission = getRequiredPermission(method, path);
            if (StringUtils.isBlank(requiredPermission)) {
                // 没有配置权限要求，说明是新接口或不需要权限
                log.warn("路径未配置权限要求：{} {}", method, path);
                return chain.filter(exchange);
            }
            
            // 6. 验证用户是否拥有所需权限
            if (userPermissions == null || !userPermissions.contains(requiredPermission)) {
                String username = (String) claims.get("username");
                log.warn("用户 {} 无权访问：{} {}，需要权限：{}", username, method, path, requiredPermission);
                return forbidden(response, "权限不足，需要权限：" + requiredPermission);
            }
            
            log.info("权限校验通过：{} {}", method, path);
            return chain.filter(exchange);
            
        } catch (Exception e) {
            log.error("权限校验异常", e);
            return forbidden(response, "权限校验失败");
        }
    }
    
    /**
     * 判断是否不需要权限校验
     */
    private boolean isNoPermissionCheckPath(String path) {
        for (String noCheckPath : NO_PERMISSION_CHECK_LIST) {
            if (path.startsWith(noCheckPath)) {
                return true;
            }
        }
        return false;
    }
    
    /**
     * 获取所需权限
     */
    private String getRequiredPermission(String method, String path) {
        // 精确匹配
        String key = method + ":" + path;
        String permission = PERMISSION_MAP.get(key);
        if (permission != null) {
            return permission;
        }
        
        // 模糊匹配（去掉路径参数）
        for (Map.Entry<String, String> entry : PERMISSION_MAP.entrySet()) {
            String pattern = entry.getKey();
            if (pathMatches(pattern, method + ":" + path)) {
                return entry.getValue();
            }
        }
        
        return null;
    }
    
    /**
     * 路径匹配（简单实现，可以用AntPathMatcher替代）
     */
    private boolean pathMatches(String pattern, String path) {
        // 支持通配符，如：GET:/api/v1/admin/books/*
        pattern = pattern.replace("*", ".*");
        return path.matches(pattern);
    }
    
    /**
     * 从请求中获取token
     */
    private String getToken(ServerHttpRequest request) {
        String authorization = request.getHeaders().getFirst("Authorization");
        if (StringUtils.isNotBlank(authorization) && authorization.startsWith("Bearer ")) {
            return authorization.substring(7);
        }
        
        String token = request.getQueryParams().getFirst("token");
        if (StringUtils.isNotBlank(token)) {
            return token;
        }
        
        return null;
    }
    
    /**
     * 返回403禁止访问
     */
    private Mono<Void> forbidden(ServerHttpResponse response, String message) {
        response.setStatusCode(HttpStatus.FORBIDDEN);
        response.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
        
        Map<String, Object> result = new HashMap<>();
        result.put("code", 403);
        result.put("errorMessage", message);
        result.put("data", null);
        
        String jsonString = JSON.toJSONString(result);
        DataBuffer buffer = response.bufferFactory().wrap(jsonString.getBytes(StandardCharsets.UTF_8));
        
        return response.writeWith(Mono.just(buffer));
    }
    
    @Override
    public int getOrder() {
        return -50; // 在AuthFilter之后执行
    }
}

